package Server;
import Conn.*;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Calendar;
import java.util.Objects;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

import DES.DES;
import Good.Good;
import Message.Message;
import RSA.RSA;
import Ticket.Ticket;

public class Server {
    ServerSocket server = null;
    int port=1002;
    public String ID="00003";

    public Ticket toTicket(String s)
    {
        String []a=s.split("-");
        Ticket m=new Ticket(a[Ticket.pos.ID_src.ordinal()],
                a[Ticket.pos.ID_dst.ordinal()],
                Integer.parseInt(a[Ticket.pos.lifetime.ordinal()]),
                a[Ticket.pos.ADC.ordinal()],
                a[Ticket.pos.key.ordinal()]
        );
        String time=a[Ticket.pos.TS.ordinal()];
        int day=Integer.parseInt(time.substring(0,2));
        int hour=Integer.parseInt(time.substring(2,4));
        int minute=Integer.parseInt(time.substring(4,6));
        Calendar c=Calendar.getInstance();
        c.set(Calendar.HOUR,hour);
        c.set(Calendar.MINUTE,minute);
        c.set(Calendar.DATE,day);
        m.setTS(c);
        return m;
    }
    public Message toMessage(String s)
    {
        String []a=s.split("\\|");
        Message m=new Message(a[Message.pos.tag.ordinal()],
                a[Message.pos.ID_src.ordinal()],
                a[Message.pos.ID_dst.ordinal()],
                Integer.parseInt(a[Message.pos.lifetime.ordinal()]),
                a[Message.pos.content.ordinal()],
                a[Message.pos.redu.ordinal()]
        );
        String time=a[Message.pos.TS.ordinal()];
        int day=Integer.parseInt(time.substring(0,2));
        int hour=Integer.parseInt(time.substring(2,4));
        int minute=Integer.parseInt(time.substring(4,6));
        Calendar c=Calendar.getInstance();
        c.set(Calendar.HOUR,hour);
        c.set(Calendar.MINUTE,minute);
        c.set(Calendar.DATE,day);
        m.setTS(c);
        return m;
    }
    //服务器打开
    public void Start() {

        try {
            server = new ServerSocket(port);
            System.out.println("正在监听端口"+port);
        } catch (IOException e) {
            e.printStackTrace();
        }
        ExecutorService pool = Executors.newFixedThreadPool(5);


        //重写接口
        class myRunnable implements Runnable {
            Conn c=new Conn();
            DataOutputStream writer = null;
            DataInputStream reader = null;
            Socket client=null;
            static int numb=0;
            Good toGood(String s)
            {
                String []a=s.split("-");
                return new Good(a[0],a[1],Integer.parseInt(a[2]),Integer.parseInt(a[3]),a[4],a[5]);
                //return g;
            }
            public Boolean isCorrect(String s)
            {
                try {
                    //解密
                    Ticket t = toTicket(s);
                    if(!Objects.equals(t.getADC(), client.getInetAddress().getHostAddress())
                            //|| !Objects.equals(t.getID_dst(), new Server().ID)
                    )
                    {
                        return false;
                    }
                }
                catch (Exception e)
                {
                    return false;
                }
                return true;
            }

            int total(Good[]a)
            {
                int t=0;
                for(Good g:a)
                {
                    t+=g.getPrice();
                }
                return t;
            }

            //
            public Message process(Message m)
            {
                String key_vd = null;
                ResultSet rs;
                Message mnull=new Message("00000",new Server().ID,m.getID_src(),5,"error"," ");
                Message newm=null;
                Ticket t=null;
                String sql;
                Good g=null;
                Ticket au;
                switch (Integer.parseInt(m.getTag()))
                {
                    case 10005:
                        sql="select x_name,x_ID,x_price,x_num,x_type,x_url from x_in ORDER by RAND() limit 1;";
                        rs=c.execute(sql);

                        try {
                            rs.next();
                            g=new Good(rs.getString(1),rs.getString(2),rs.getInt(3),rs.getInt(4), rs.getString(5), rs.getString(6));
                            newm=new Message("30005",new Server().ID,m.getID_src(),5,g.toStr()," ");
                        } catch (SQLException e) {
                            newm=new Message("00000",new Server().ID,m.getID_src(),5,"error"," ");
                            e.printStackTrace();
                        }
                        break;
                        //购买
                    case 10010:
                        sql="select p_ID,u_ID,x_price,x_num,x_ID,x_name from pur_history where u_ID='%s' limit %d,%d"
                                .formatted(m.getID_src(),Integer.parseInt(m.getRedu()),Integer.parseInt(m.getRedu()));
                        rs=c.execute(sql);
                        try {
                            rs.next();
                            newm=new Message("30010",new Server().ID,m.getID_src(),2,
                                    new Good(rs.getString(6),rs.getString(5), rs.getInt(3), rs.getInt(4), " ", " ").toStr(),
                                    rs.getString(1));
                        } catch (SQLException e) {
                            e.printStackTrace();
                            newm=new Message("00000",new Server().ID,m.getID_src(),5,"error"," ");
                        }
                        break;
                    case 10001:
                        //String x_ID=m.getContent();
                        g=toGood(m.getContent());
                        int x_num=g.getNum();
                        int price=g.getPrice();
                        sql="select x_num from x_in where x_id='%s'".formatted(g.getID());
                        rs=c.execute(sql);
                        try {
                            rs.next();
                            int num=rs.getInt(1)-x_num;
                            sql="update x_in set x_num=%d where x_ID='%s'".formatted(num,g.getID());
                            c.execute(sql,1);
                        } catch (SQLException e) {
                            e.printStackTrace();
                        }
                        //添加购买记录
                        sql="select * from pur_history;";
                        rs=c.execute(sql);
                        String row="";
                        try {
                            while(rs.next())
                            {
                                //row= String.valueOf(rs.get()+1);
                                row=String.valueOf(rs.getInt(1)+1);
                            }
                        } catch (SQLException e) {
                            e.printStackTrace();
                        }
                        sql="insert into pur_history(p_ID,u_ID,x_price,x_num,x_ID,x_name) value ('%s','%s',%d,%d,'%s','%s')"
                                .formatted(row,m.getID_src(),price,x_num,g.getID(),g.getName());
                        c.execute(sql,1);
                        sql="select u_charge from u_in where u_ID='%s';".formatted(m.getID_src());
                        int charge=0;
                        try {
                            rs=c.execute(sql);
                            rs.next();
                            charge=rs.getInt(1);

                        } catch (SQLException e) {
                            e.printStackTrace();
                        }
                        sql="update u_in set u_charge=%d where u_ID='%s'"
                                .formatted(charge-price,m.getID_src());
                        c.execute(sql,1);
                        newm=new Message("30001",new Server().ID,m.getID_src(),5,String.valueOf(price)," ");
                        break;
                    case 10007:
                        String name=m.getContent();
                        sql="select x_name,x_ID,x_price,x_num,x_type,x_url from x_in where x_name='%s' order by rand()  limit 1;".formatted(name);
                        rs= c.execute(sql);
                        try {
                            rs.next();
                            g=new Good(rs.getString(1),rs.getString(2),rs.getInt(3),rs.getInt(4),rs.getString(5),rs.getString(6));


                            newm=new Message("30007",new Server().ID,m.getID_src(),5,g.toStr()," ");
                        } catch (SQLException e) {
                            newm=new Message("00000",new Server().ID,m.getID_src(),5,"error"," ");
                            e.printStackTrace();
                        }

                        break;
                    case 10006:
                        String type=m.getContent();
                        sql="select x_name,x_ID,x_price,x_num,x_type,x_url from x_in where x_type='%s' order by rand()  limit 1;".formatted(type);
                        rs= c.execute(sql);
                        try {
                            rs.next();
                            g=new Good(rs.getString(1),rs.getString(2),rs.getInt(3),rs.getInt(4),rs.getString(5),rs.getString(6));


                            newm=new Message("30006",new Server().ID,m.getID_src(),5,g.toStr()," ");
                        } catch (SQLException e) {
                            newm=new Message("00000",new Server().ID,m.getID_src(),5,"error"," ");
                            e.printStackTrace();
                        }
                        break;
                        //退货
                    case 10002:
                        String p_ID=m.getContent();
                        sql="select p_ID,u_ID,x_price,x_num,x_ID,x_name from pur_history where p_ID='%s'"
                                .formatted(p_ID);
                        rs=c.execute(sql);
                        int pprice=0;
                        int pnum=0;
                        String gID;
                        try {
                            rs.next();
                            pprice=rs.getInt(3);
                            pnum=rs.getInt(4);
                            gID=rs.getString(5);
                        } catch (SQLException e) {
                            e.printStackTrace();
                            break;
                        }
                        sql="select x_num from x_in where x_id='%s'".formatted(gID);
                        rs=c.execute(sql);
                        try {
                            rs.next();
                            int num=rs.getInt(1)+pnum;
                            sql="update x_in set x_num=%d where x_ID='%s'".formatted(num,p_ID);
                            c.execute(sql,1);
                        } catch (SQLException e) {
                            e.printStackTrace();
                            newm=new Message("00000",new Server().ID,m.getID_src(),5,"error"," ");
                            break;
                        }
                        sql="select u_charge from u_in where u_id='%s';".formatted(m.getID_src());
                        charge=0;
                        try {
                            rs=c.execute(sql);
                            rs.next();
                            charge=rs.getInt(1);
                        } catch (SQLException e) {
                            e.printStackTrace();
                            newm=new Message("00000",new Server().ID,m.getID_src(),5,"error"," ");
                            break;
                        }

                        sql="update u_in set u_charge=%d where u_ID='%s'"
                                .formatted(charge+pprice,m.getID_src());
                        c.execute(sql,1);
                        //操作数据库
                        sql="DELETE FROM pur_history where p_id = '%s';".formatted(p_ID);
                        c.execute(sql,1);
                        newm=new Message("30002",new Server().ID,m.getID_src(),5,"success"," ");
                        break;
                    case 10003:
                        int money=Integer.parseInt(m.getContent());

                        sql="select u_charge from u_in where u_id='%s';".formatted(m.getID_src());
                        rs=c.execute(sql);
                        try {
                            rs.next();
                            money+=rs.getInt(1);
                        } catch (SQLException e) {
                            e.printStackTrace();
                            newm=new Message("00000",new Server().ID,m.getID_src(),5,"error"," ");
                        }
                        sql="update u_in set u_charge=%d where u_ID='%s';".formatted(money,m.getID_src());
                        c.execute(sql,1);
                        //databasex``
                        newm=new Message("30003",new Server().ID,m.getID_src(),5,String.valueOf(money)," ");
                        break;
                    case 10004:
                        String npsw;
                        npsw = m.getContent();
                        sql="update u_in set u_pas='%s' where u_ID='%s';".formatted(npsw,m.getID_src());
                        c.execute(sql,1);
                        //
                        newm=new Message("30002",new Server().ID,m.getID_src(),5,"success"," ");
                        break;
                    case 20001:
                        g=toGood(m.getContent());
                        sql="INSERT INTO x_in(X_ID, X_NAME, X_PRICE,x_URL,x_num,x_type) VALUES ('%s', '%s', %d,'%s',%d,'%s');"
                                .formatted(g.getID(),g.getName(),g.getPrice(),g.getURL(),g.getNum(),g.getType());
                        c.execute(sql,1);

                        //操作数据库
                        newm=new Message("31001",new Server().ID,m.getID_src(), m.getLifetime(),"success"," ");
                        break;
                    case 20002:
                        //操作数据库
                        String x_ID=m.getContent();
                        x_num= Integer.parseInt(m.getRedu());
                        sql="select x_num from x_in where x_iD='%s';".formatted(x_ID);
                        rs=c.execute(sql);
                        try {
                            rs.next();
                            x_num=x_num+rs.getInt(1);
                            sql="update x_in set x_num=%d where x_ID='%s'".formatted(x_num,x_ID);
                            c.execute(sql,1);
                        } catch (SQLException e) {
                            e.printStackTrace();
                        }
                        newm=new Message("31002",new Server().ID,m.getID_src(), m.getLifetime(),"success"," ");
                        break;

                    case 20004:
                        int num= Integer.parseInt(m.getRedu());
                        sql="select x_name,x_ID,x_price,x_num,x_type,x_url from x_in  limit %d,1;".formatted(num);
                        rs= c.execute(sql);
                        try {
                            rs.next();
                            g=new Good(rs.getString(1),rs.getString(2),rs.getInt(3),rs.getInt(4),rs.getString(5),rs.getString(6));

                            newm=new Message("31004",new Server().ID,m.getID_src(),5,g.toStr()," ");
                        } catch (SQLException e) {
                            newm=new Message("00000",new Server().ID,m.getID_src(),5,"error"," ");
                            e.printStackTrace();
                        }
                        break;
                    case 1:
                        if(Objects.equals(m.getID_dst(), new Server().ID))
                        {
                            t=new Ticket(new Server().ID,m.getID_src(),120,client.getInetAddress().getHostAddress(),"key");
                            newm=new Message("0000",new Server().ID,m.getID_src(),120,t.toStr(),"key");
                        }
                        break;
                    case 7:
                        try {
                            t=toTicket(DES.decrypt(m.getContent(),DES.getSecretKey("00003")));
                            key_vd=t.getKey();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        String ID=m.getID_src();
                        try {
                            RSA.decrypt(m.getRedu(),key_vd);
                            au=toTicket(RSA.decrypt(m.getRedu(),key_vd));
                        } catch (Exception e) {
                            e.printStackTrace();
                            return mnull;

                        }
                        type="type";
                        sql="SELECT u_charge FROM u_in where U_ID = '"+m.getID_src()+"' and U_PAS = '"+au.getKey()+"';";
                        rs=c.execute(sql);
                        try {
                            rs.next();
                            type=rs.getString(1);
                        } catch (SQLException e) {
                            e.printStackTrace();
                            newm=new Message("00000",new Server().ID,m.getID_src(),5,"error"," ");
                            break;
                        }
//                        if(rs==null)
//                        {
//                            newm=new Message("00000",new Server().ID,m.getID_src(),5,"error"," ");
//                            break;
//                        }
                        newm=new Message("00008",new Server().ID,m.getID_src(),5,type," ");
                        break;
                    case 8:
                        break;
                    case 20003:
                        sql="select p_ID,u_ID,x_price,x_num,x_ID,x_name from pur_history limit %d,%d"
                                .formatted(Integer.parseInt(m.getRedu()),Integer.parseInt(m.getRedu()));
                        rs=c.execute(sql);
                        try {
                            rs.next();
                            newm=new Message("31003",new Server().ID,m.getID_src(),2,
                                    new Good(rs.getString(6),rs.getString(5), rs.getInt(3), rs.getInt(4), " ", rs.getString(2)).toStr(),
                                    rs.getString(1));
                        } catch (SQLException e) {
                            e.printStackTrace();
                            newm=new Message("00000",new Server().ID,m.getID_src(),5,"error"," ");
                        }
                        break;
                    case 13:
                        try {
                            t=toTicket(DES.decrypt(m.getContent(),DES.getSecretKey("00003")));
                            key_vd=t.getKey();
                        } catch (Exception e) {
                            e.printStackTrace();
                            return mnull;
                        }
                        ID=m.getID_src();
                        try {
                            RSA.decrypt(m.getRedu(),key_vd);
                            au=toTicket(RSA.decrypt(m.getRedu(),key_vd));
                        } catch (Exception e) {
                            e.printStackTrace();
                            return mnull;
                        }
                        type="type";
                        //sql="SELECT u_charge FROM u_in where U_ID = '"+m.getID_src()+"' and U_PAS = '"+au.getKey()+"';";
                        sql="insert into u_in(u_ID,u_pas,u_charge,u_type) values('%s','%s',0,0)"
                                .formatted(m.getID_src(),au.getKey());
                        try{
                            c.execute(sql, 1);
                        }catch (Exception e)
                        {
                            newm=new Message("00000",new Server().ID,m.getID_src(),5,"error"," ");
                        }
                        newm=new Message("000020",new Server().ID,m.getID_src(),5,"success"," ");
                        break;
                    default:
                        newm=new Message("00000",new Server().ID,m.getID_src(),5,"error"," ");
                }
                return newm;
            }
            public void send(String s)
            {
                try {
                    writer.writeUTF(s);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            public String recv()
            {
                try {
                    return reader.readUTF();
                } catch (IOException e) {
                    return "";
                }
            }
            myRunnable(Socket nclient)
            {
                this.client = nclient;
                numb++;
                try {
                    DataOutputStream writer = new DataOutputStream(this.client.getOutputStream());
                    DataInputStream reader = new DataInputStream(this.client.getInputStream());
                    this.writer=writer;
                    this.reader=reader;
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            @Override
            public void run()
            {
                c.getConnection();
                Message m;
                Ticket t;
                System.out.println(Thread.currentThread().getName());
                System.out.println("serve for " + this.client.getInetAddress()+",linked with "+numb+" clinets");
                try
                {
                    while(true)
                    {
                        String s=recv();
                        if( s.equals(""))
                        {
                            break;
                        }
                        m=toMessage(s);
                        System.out.println(isCorrect(m.getContent()));
                        System.out.println("recv from client: "+m.toStr());
                        String k=" ";
                        //t=new Ticket(new Server().ID,m.getID_src(),5,client.getInetAddress().getHostAddress(),"key");
                        //System.out.println("send to client "+t.toStr());
                        m=process(m);
                        send(m.toStr());
                    }

                    client.close();
                    numb--;
                    System.out.println("client close\n");
                } catch (IOException e) {
                    e.printStackTrace();
                }

                //client.close();
            }
        } //重写Runnable接口


        //循环等待socket连接
        while(true){
            try {
                Socket new_client= server.accept();
                pool.execute(new myRunnable(new_client));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
